package com.qwt.part_time_api.filter;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.qwt.part_time_api.error.ErrorCode;
import com.qwt.part_time_api.service.RoleService;
import com.qwt.part_time_api.utils.JwtUtil;
import com.qwt.part_time_api.vo.Result;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * JWT过滤器,使用token换取权限信息
 *
 * @author 君子慎独
 */
@Slf4j
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {

    @Autowired
    private RoleService roleService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("jwt过滤器");
        //设置编码格式
        response.setContentType("text/json;charset=utf-8");
        //获取jwt
        String jwt = request.getHeader(JwtUtil.getHeader());

        if (StringUtils.isEmpty(jwt)) {
            log.info("jwt为空");
            //如果jwt为空，则过滤链继续往下执行
            // 为空就代表 该访问的地址不需要token 也就说不用登录即可访问
            chain.doFilter(request, response);
            return;
        }

        // 解析
        Claims claims = JwtUtil.parseToken(jwt);

        //判断jwt是否被篡改、是否解析异常
        if (claims == null) {
            log.info("jwt不合法");
            response.getWriter().write(JSON.toJSONString(Result.fail(ErrorCode.TOKEN_TOKEN_ERROR.getErrCode(), ErrorCode.TOKEN_TOKEN_ERROR.getErrMsg())));
            return;
        }

        // 刷新token 规定时间内无需重复登陆
        String s = redisTemplate.opsForValue().get("QWT-TOKEN_" + claims.getSubject());

        // 如果为空 证明可刷新时间到了 或是 退出登录了 那么就要重新登录
        if (StringUtils.isEmpty(s)) {
            log.info("redis里面的token为空");
            //直接放行 默认未登录
            chain.doFilter(request, response);
            return;
        }

        //判断jwt是否过期 redis里面的token与前端传的是否一致
        if (JwtUtil.isExpiration(claims) && Objects.equals(s, jwt)) {
            log.info("刷新jwt");
            //返回给前端刷新后的token 让前端获取后换上 然后重新请求
            String newToken = JwtUtil.refreshToken(jwt);
            //重新更新一下登陆状态
            redisTemplate.opsForValue().set(claims.getSubject() + "_QWT-STATE", "1", 2, TimeUnit.HOURS);
            // 获取倒计时
            Long ttl = redisTemplate.opsForValue().getOperations().getExpire("QWT-TOKEN_" + claims.getSubject());
            // 将新token存入 同时减少时间
            redisTemplate.opsForValue().set("QWT-TOKEN_" + claims.getSubject(), JSON.toJSONString(newToken), ttl, TimeUnit.SECONDS);
            //返回
            response.getWriter().write(JSON.toJSONString(Result.success(newToken)));
            return;
        } else if (JwtUtil.isExpiration(claims)) {
            log.info("jwt过期");
            response.getWriter().write(JSON.toJSONString(Result.fail(ErrorCode.TOKEN_TIME_OUT.getErrCode(), ErrorCode.TOKEN_TIME_OUT.getErrMsg())));
            return;
        }

        String code;
        //用户、角色、资源方案：使用角色控制权限 获取角色
        code = roleService.findRoleNameByAccount(claims.getSubject());

        List<GrantedAuthority> authorities = new ArrayList<>();

        // 授权
        SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(code);
        authorities.add(simpleGrantedAuthority);

        // 用户的认证 会生成一个token
        // 这个token被传递给AuthenticationManager进行验证
        UsernamePasswordAuthenticationToken token
                = new UsernamePasswordAuthenticationToken(claims.getSubject(), null, authorities);
        //根据上下文，获取用户的权限，实现自动登录
        SecurityContextHolder.getContext().setAuthentication(token);
        chain.doFilter(request, response);
    }
}


